Skip to content

Raise a descriptive ArgumentError from <=> for incompatible units#32

Merged
nertzy merged 1 commit into
minad:masterfrom
nertzy:comparison-incompatible-dimensions
Jun 12, 2026
Merged

Raise a descriptive ArgumentError from <=> for incompatible units#32
nertzy merged 1 commit into
minad:masterfrom
nertzy:comparison-incompatible-dimensions

Conversation

@nertzy

@nertzy nertzy commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Following up on #31: <=> now returns nil for non-coercible objects, but the Numeric branch still raised IncompatibleUnitError (a TypeError) whenever two units had incompatible dimensions. Routed through Comparable that surfaced as the unhelpful comparison of Unit with Unit failed, and sort, min, max, between? and clamp blew up with a non-standard error.

Raise ArgumentError directly from <=> when the operands are dimensionally incompatible. Every Comparable path funnels through <=>, so one descriptive message now surfaces consistently from <, >, sort, min, max, between? and clamp.

Operands are labelled following core Ruby's own phrasing, symmetrically in both directions: a dimensional Unit is shown via #inspect, while a bare numeric — or a dimensionless unit, which is just a number and is how a coerced bare numeric arrives — is shown by its class. This avoids splatting an arbitrary #inspect into the message or printing a confusing coerced Unit("1.2").

Unit(1, 'm') <=> Unit(1, 's')     # comparison of Unit("1 m") with Unit("1 s") failed
Unit(1, 'm') > 1.2                # comparison of Unit("1 m") with Float failed
1.2 > Unit(1, 'm')                # comparison of Float with Unit("1 m") failed
[Unit(1, 'm'), Unit(2, 's')].sort # ArgumentError (same message, via <=>)
Unit(100, 'cm') <=> Unit(1, 'm')  # 0  (compatible — unchanged)
[Unit(3,'m'), Unit(1,'m')].sort   # works

Comparing against a genuinely foreign object (nil, a String) still returns nil from <=>, matching 1 <=> "a" — only dimension mismatches between quantities raise. Arithmetic (+/-) deliberately keeps raising IncompatibleUnitError.

@nertzy nertzy force-pushed the comparison-incompatible-dimensions branch from b3c7c8e to 4741402 Compare June 12, 2026 22:52
@nertzy nertzy changed the title Return nil from <=> for units with incompatible dimensions Raise a descriptive ArgumentError from <=> for incompatible units Jun 12, 2026
Following minad#31, <=> returned nil for non-coercible objects, but the
Numeric branch still raised IncompatibleUnitError (a TypeError) whenever
two units had incompatible dimensions. Routed through Comparable that
surfaced as the unhelpful "comparison of Unit with Unit failed", and
sort, min, max, between? and clamp blew up with a non-standard error.

Raise ArgumentError directly from <=> when the operands are dimensionally
incompatible. Every Comparable path funnels through <=>, so the same
descriptive message now surfaces from <, >, sort, min, max, between? and
clamp. A sibling Unit is shown via #inspect (Unit("1 s")); any other
numeric is shown by class (Float, Integer) rather than its coerced unit
or a potentially large #inspect, matching core Ruby's own phrasing.

Comparing against a genuinely foreign object (nil, String) still returns
nil, matching 1 <=> "a"; only dimension mismatches between quantities
raise. Arithmetic (+/-) keeps raising IncompatibleUnitError.
@nertzy nertzy force-pushed the comparison-incompatible-dimensions branch from 4741402 to 16c2bcb Compare June 12, 2026 22:56
@nertzy nertzy merged commit ec81aa2 into minad:master Jun 12, 2026
4 checks passed
@nertzy nertzy deleted the comparison-incompatible-dimensions branch June 15, 2026 20:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant